//
// Created by whg on 2025-06-02.
//

#include <stdio.h>

#include "interpreter.hpp"
#include "code/byteCode.hpp"
#include "object/pyInteger.hpp"
#include "global.hpp"
#include "functionObject.hpp"

#define PUSH(x)  _frame->stack()->push((x))
#define POP()    _frame->stack()->pop()

#define PY_TRUE     Global::PyTrue
#define PY_FALSE    Global::PyFalse
#define PY_NONE     Global::PyNone
#define PRINT_FUNC  Global::PrintFunc

Interpreter::Interpreter() {
    _builtins = new Map<PyObject*, PyObject*>();
    _builtins->put(new PyString("True"), PY_TRUE);
    _builtins->put(new PyString("False"), PY_FALSE);
    _builtins->put(new PyString("None"), PY_NONE);

    _builtins->put(new PyString("len"), new FunctionObject(len));
    _builtins->put(new PyString("print"), new FunctionObject(print));
}

void Interpreter::run(CodeObject* code) {
    _frame = new FrameObject(code);
    while(_frame->hasMoreCode()){
        int pc = getPc();
        unsigned char opCode = _frame->getOpCode();
        int opArg = _frame->getOpArg();

        PyInteger* lhs, * rhs;
        PyObject* v, * w, * u, * attr;
        FunctionObject* fo;
        ArrayList<PyObject*>* args = nullptr;
        PyList* list;

        // printf("%2d %5d %2d\n", pc, opCode, opArg);
        switch (opCode) {
            case ByteCode::POP_TOP:
                POP();
                break;

            case ByteCode::BINARY_ADD:
                v = POP();
                w = POP();
                PUSH(w->add(v));
                break;

            case ByteCode::LOAD_CONST:
                v = _frame->consts()->get(opArg);
                PUSH(v);
                break;
            case ByteCode::LOAD_NAME:
                v = names()->get(opArg);
                w = locals()->get(v);
                if(w == PY_NONE){
                    w = globals()->get(v);
                    if(w == PY_NONE){
                        w = _builtins->get(v);
                    }
                }
                PUSH(w);
                break;
            case ByteCode::STORE_NAME:
                v = names()->get(opArg);
                locals()->put(v, POP());
                break;

            case ByteCode::BUILD_TUPLE:
                list = new PyList();
                while(opArg--){
                    list->append(POP());
                }
                PUSH(list);
                break;

            case ByteCode::COMPARE_OP:
                w = POP();
                v = POP();

                switch (opArg) {
                    case ByteCode::LESS:
                        PUSH(v->less(w));
                        break;
                    case ByteCode::EQUAL:
                        PUSH(v->equal(w));
                        break;
                    case ByteCode::GREATER:
                        PUSH(v->greater(w));
                        break;
                    case ByteCode::IS:
                        if(v == w){
                            PUSH(PY_TRUE);
                        }else{
                            PUSH(PY_FALSE);
                        }
                        break;
                    default:
                        printf("compare error: Unknown opArg = %d\n", opArg);
                }
                break;

            case ByteCode::JUMP_FORWARD:
                setPc(getPc() + opArg);
                break;

            case ByteCode::JUMP_ABSOLUTE:
                setPc(opArg);
                break;

            case ByteCode::POP_JUMP_IF_FALSE:
                v = POP();
                if(v == PY_FALSE){
                    setPc(opArg);
                }
                break;

            case ByteCode::LOAD_GLOBAL:
                v = names()->get(opArg);
                w = globals()->get(v);
                if(w == PY_NONE){
                    w = _builtins->get(v);
                }
                PUSH(w);
                break;
            case ByteCode::STORE_GLOBAL:
                v = names()->get(opArg);
                globals()->put(v, POP());
                break;

            case ByteCode::LOAD_FAST:
                v = fastLocals()->get(opArg);
                PUSH(v);
                break;
            case ByteCode::STORE_FAST:
                fastLocals()->set(opArg, POP());
                break;

            case ByteCode::LOAD_ATTR:
            case ByteCode::LOAD_METHOD:
                v = POP();
                w = names()->get(opArg);
                PUSH(v->getAttr(w));
                break;

            case ByteCode::MAKE_FUNCTION:
                w = POP(); // function name
                v = POP();
                fo = new FunctionObject(v);
                fo->setGlobals(_frame->globals());

                if(opArg == 1){
                    PyList* t = (PyList*)POP();
                    args = new ArrayList<PyObject*>();
                    for(int i=0;i<t->length();i++){
                        args->add(t->get(i));
                    }
                }
                fo->setDefaults(args);

                PUSH(fo);
                if(args != nullptr){
                    delete args;
                    args = nullptr;
                }
                break;

            case ByteCode::CALL_METHOD:
            case ByteCode::CALL_FUNCTION:
                if(opArg > 0){
                    // 根据 opArg 去栈里取出参数，然后放到 args 列表里
                    args = new ArrayList<PyObject*>(opArg);
                    while(opArg--){
                        args->set(opArg, POP());
                    }
                }

                v = POP();
                fo = static_cast<FunctionObject*>(v);
                newFrame(fo, args);

                if(args != nullptr){
                    delete args;
                    args = nullptr;
                }
                break;
            case ByteCode::RETURN_VALUE:
                delFrame(POP());
                if(!_frame){
                    return;
                }
                break;

            default:
                printf("run error: Unknown opCode = %d\n", opCode);
        }
    }
}

void Interpreter::newFrame(FunctionObject* func, ArrayList<PyObject*>* args) {
    if(func->klass() == NativeFunctionKlass::getInstance()){
        PUSH(func->call(args));
    }else if(func->klass() == MethodKlass::getInstance()){
        MethodObject* method = (MethodObject*) func;
        if(!args){
            args = new ArrayList<PyObject*>(1);
        }
        args->insert(0, method->owner());
        newFrame(method->func(), args);
    }else if(func->klass() == FunctionKlass::getInstance()){
        FrameObject* frame = new FrameObject(func, args);
        frame->setNextFrame(_frame); // 关联之前未执行完的栈帧，即设置其为下一个栈帧
        _frame = frame; // 令新的栈帧成为栈顶，即当前正在执行的栈帧，类似入栈（设置栈顶指针指向新的）
    }
}

void Interpreter::delFrame(PyObject *returnValue) {
    if(!_frame->nextFrame()){
        delete _frame;
        _frame = nullptr;
        return;
    }

    FrameObject* last = _frame;
    _frame = _frame->nextFrame(); // 把下一个栈帧设成栈顶，即当前正在执行的栈帧，类似出栈（设置栈顶指针指向下一个）
    PUSH(returnValue);
    delete last;
}
